﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Collections;

namespace Rud.Holmgren.TabulexLib
{
    interface ITbxModelSerializer
    {
        T DeSerialize<T>(string json) where T : class;
    }

    class TbxFastJsonModelSerializer : ITbxModelSerializer
    {
        private object BuildValue(Type type, object value)
        {
            if (type == typeof(string))
            {
                return value != null ? value.ToString() : null;
            }
            else if (type == typeof(int))
            {
                return Convert.ToInt32(value);
            }
            else if (type == typeof(DateTime))
            {
                return TbxUtil.FromTbxTime(Convert.ToInt64(value));
            }
            else if (typeof(IList).IsAssignableFrom(type))
            {
                var elementType = type.GetGenericArguments().First();
                var list = Activator.CreateInstance(type) as IList;

                foreach (var elm in ((IEnumerable<object>)value))
                {
                    list.Add(BuildValue(elementType, elm));
                }

                return list;
            }
            else if (type.IsClass)
            {
                return BuildObject(type, value as IDictionary<string, object>);
            }
            else
            {
                throw new ApplicationException("Unsupported type: " + type.Name);
            }
        }

        private object BuildObject(Type type, IDictionary<string, object> data)
        {
            var retval = Activator.CreateInstance(type);
            var props = type.GetProperties().ToDictionary(p => p.Name);

            foreach (var f in data)
            {
                if (props.ContainsKey(f.Key))
                {
                    var prop = props[f.Key];
                    var value = BuildValue(prop.PropertyType, f.Value);

                    prop.SetValue(retval, value, null);
                }
            }

            return retval;
        }

        public T DeSerialize<T>(string json) where T : class
        {
            var parser = new fastJSON.JsonParser(json, true);
            var data = parser.Decode();

            return (T)BuildValue(typeof(T), data);
        }
    }
}
